package com.cctc.rds.nrpc.core.protocol.message.impl;

import com.cctc.rds.nrpc.api.rpc.RpcRequest;
import com.cctc.rds.nrpc.core.protocol.message.MessageType;
import com.cctc.rds.nrpc.core.util.JsonUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.netty.util.internal.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.HashMap;
import java.util.Map;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RpcRequestMessage extends AbstractMessage {
    private String txid;
    @JsonIgnore
    private transient RpcRequest rpcRequest;
    private Map<String, String> body;

    public RpcRequestMessage(RpcRequest rpcRequest) {
        setRpcRequest(rpcRequest);
    }

    @Override
    public Byte getType() {
        return MessageType.REQUEST.getValue();
    }

    public void setRpcRequest(RpcRequest rpcRequest) {
        this.rpcRequest = rpcRequest;
        this.body = new HashMap<>();
        if (rpcRequest.getInterfaces() == null) return;
        this.body.put("interfaces", rpcRequest.getInterfaces().getName());
        this.body.put("methodName", rpcRequest.getMethodName());
        if (rpcRequest.getParameterTypes() != null && rpcRequest.getParameterTypes().length > 0) {
            String[] parameterTypesJsonArray = new String[rpcRequest.getParameterTypes().length];
            for (int i = 0; i < rpcRequest.getParameterTypes().length; i++) {
                parameterTypesJsonArray[i] = rpcRequest.getParameterTypes()[i].getName();
            }
            this.body.put("parameterTypes", JsonUtils.toJson(parameterTypesJsonArray));
            if (rpcRequest.getArguments() != null && rpcRequest.getArguments().length > 0) {
                String[] argumentsJsonArray = new String[rpcRequest.getArguments().length];
                for (int i = 0; i < rpcRequest.getArguments().length; i++) {
                    argumentsJsonArray[i] = JsonUtils.toJson(rpcRequest.getArguments()[i]);
                }
                this.body.put("arguments", JsonUtils.toJson(argumentsJsonArray));
            }
        }
    }

    public RpcRequest getRpcRequest() {
        if (rpcRequest == null && this.body != null) {
            rpcRequest = RpcRequest.builder().build();
            try {
                rpcRequest.setInterfaces(Class.forName(this.body.get("interfaces")));
                rpcRequest.setMethodName(this.body.get("methodName"));
                String parameterTypesJsonStr = this.body.get("parameterTypes");
                String argumentsJsonStr = this.body.get("arguments");
                if (StringUtil.isNullOrEmpty(parameterTypesJsonStr)) {
                    String[] parameterTypesJsonArray = JsonUtils.fromJsonList(parameterTypesJsonStr, String.class).toArray(new String[0]);
                    String[] argumentsJsonArray = JsonUtils.fromJsonList(argumentsJsonStr, String.class).toArray(new String[0]);
                    Class<?>[] parameterTypes = new Class[parameterTypesJsonArray.length];
                    Object[] arguments = new Object[argumentsJsonArray.length];
                    for (int i = 0; i < parameterTypesJsonArray.length; i++) {
                        parameterTypes[i] = Class.forName(parameterTypesJsonArray[i]);
                        if (i < argumentsJsonArray.length && StringUtil.isNullOrEmpty(argumentsJsonArray[i])) {
                            arguments[i] = JsonUtils.fromJson(argumentsJsonArray[i], parameterTypes[i]);
                        }
                    }
                    rpcRequest.setParameterTypes(parameterTypes);
                    rpcRequest.setArguments(arguments);
                }
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
        return rpcRequest;
    }

}
